package com.ffcs.crmd.tsp.core.netty;

import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import com.ffcs.crmd.tsp.api.dto.netty.RemotingCommand;
import com.ffcs.crmd.tsp.api.netty.INettyInvokeCallback;

/**
 * 
 * 功能说明:请求应答封装
 *
 * @author ZHONGFUHUA
 * 
 * @since 1.0.0-SNAPSHOT
 *
 */
public class ResponseFuture {
    
    /**
     * 自定义netty通信体对象
     */
    private volatile RemotingCommand responseCommand;
    
    /**
     * 发送请求是否成功
     */
    private volatile boolean         sendRequestOK           = false;
    
    /**
     * 通信调用回复异常
     */
    private volatile Throwable       cause;
    
    /**
     * 每次通信的标识号
     */
    private int                      opaque;
    
    /**
     * 请求操作代码
     */
    private int                      code;
    
    /**
     * 等待请求应答超时时间
     */
    private long                     timeoutMillis;
    
    /**
     * 保证信号量至多至少只被释放一次
     */
    private SemaphoreReleaseOnlyOnce once;
    
    /**
     * 回调方法
     */
    private INettyInvokeCallback     invokeCallback;
    
    /**
     * 开始时间
     */
    private final long               beginTimestamp          = System.currentTimeMillis();
    
    /**
     * 阻塞线程计数器
     */
    private final CountDownLatch     countDownLatch          = new CountDownLatch(1);
    
    /**
     * 保证回调的callback方法至多至少只被执行一次f
     */
    private final AtomicBoolean      executeCallbackOnlyOnce = new AtomicBoolean(false);
    
    public ResponseFuture(int opaque, int code, long timeoutMillis) {
        this(opaque, code, timeoutMillis, null, null);
    }
    
    public ResponseFuture(int opaque, int code, long timeoutMillis, SemaphoreReleaseOnlyOnce once, INettyInvokeCallback invokeCallback) {
        this.invokeCallback = invokeCallback;
        this.once = once;
        this.code = code;
        this.opaque = opaque;
        this.timeoutMillis = timeoutMillis;
    }
    
    /**
     * 
     * 功能说明:执行回调方法
     * 
     */
    public void executeInvokeCallback() {
        if (invokeCallback != null) {
            if (this.executeCallbackOnlyOnce.compareAndSet(false, true)) {
                invokeCallback.operationComplete(this.responseCommand);
            }
        }
    }
    
    /**
     * 
     * 功能说明:释放信号量
     *
     */
    public void release() {
        if (this.once != null) {
            this.once.release();
        }
    }
    
    /**
     * 
     * 功能说明:是否超时
     * 
     */
    public boolean isTimeout() {
        if (timeoutMillis <= 0) {
            return false;
        }
        long diff = System.currentTimeMillis() - this.beginTimestamp;
        return ((diff + 1000) > this.timeoutMillis);
    }
    
    /**
     * 
     * 功能说明:等待指定时间服务器回应
     * 
     */
    public RemotingCommand waitResponse() throws InterruptedException {
        this.countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
        return this.responseCommand;
    }
    
    /**
     * 
     * 功能说明:存入服务器回应的通信体
     * 
     */
    public void putResponse(RemotingCommand responseCommand) {
        this.responseCommand = responseCommand;
        this.countDownLatch.countDown();
    }
    
    /**
     * 功能说明: 获取开始时间
     *
     * @return beginTimestamp 开始时间
     */
    public long getBeginTimestamp() {
        return beginTimestamp;
    }
    
    /**
     * 功能说明: 获取发送请求是否成功
     *
     * @return sendRequestOK 发送请求是否成功
     */
    public boolean isSendRequestOK() {
        return sendRequestOK;
    }
    
    /**
     * 功能说明: 设置发送请求是否成功
     *
     * @param sendRequestOK 发送请求是否成功
     */
    public void setSendRequestOK(boolean sendRequestOK) {
        this.sendRequestOK = sendRequestOK;
    }
    
    /**
     * 功能说明: 获取等待请求应答超时时间
     *
     * @return timeoutMillis 等待请求应答超时时间
     */
    public long getTimeoutMillis() {
        return timeoutMillis;
    }
    
    /**
     * 功能说明: 设置等待请求应答超时时间
     *
     * @param timeoutMillis 等待请求应答超时时间
     */
    public void setTimeoutMillis(long timeoutMillis) {
        this.timeoutMillis = timeoutMillis;
    }
    
    /**
     * 功能说明: 获取通信调用回复异常
     *
     * @return cause 通信调用回复异常
     */
    public Throwable getCause() {
        return cause;
    }
    
    /**
     * 功能说明: 设置通信调用回复异常
     *
     * @param cause 通信调用回复异常
     */
    public void setCause(Throwable cause) {
        this.cause = cause;
    }
    
    /**
     * 功能说明: 获取自定义netty通信体对象
     *
     * @return responseCommand 自定义netty通信体对象
     */
    public RemotingCommand getResponseCommand() {
        return responseCommand;
    }
    
    /**
     * 功能说明: 设置自定义netty通信体对象
     *
     * @param responseCommand 自定义netty通信体对象
     */
    public void setResponseCommand(RemotingCommand responseCommand) {
        this.responseCommand = responseCommand;
    }
    
    /**
     * 功能说明: 获取每次通信的标识号
     *
     * @return opaque 每次通信的标识号
     */
    public int getOpaque() {
        return opaque;
    }
    
    /**
     * 功能说明: 设置每次通信的标识号
     *
     * @param opaque 每次通信的标识号
     */
    public void setOpaque(int opaque) {
        this.opaque = opaque;
    }
    
    /**
     * 功能说明: 获取请求操作代码
     *
     * @return code 请求操作代码
     */
    public int getCode() {
        return code;
    }
    
    /**
     * 功能说明: 设置请求操作代码
     *
     * @param code 请求操作代码
     */
    public void setCode(int code) {
        this.code = code;
    }
    
    /**
     * 功能说明: 获取保证信号量至多至少只被释放一次
     *
     * @return once 保证信号量至多至少只被释放一次
     */
    public SemaphoreReleaseOnlyOnce getOnce() {
        return once;
    }
    
    /**
     * 功能说明: 设置保证信号量至多至少只被释放一次
     *
     * @param once 保证信号量至多至少只被释放一次
     */
    public void setOnce(SemaphoreReleaseOnlyOnce once) {
        this.once = once;
    }
    
    /**
     * 功能说明: 获取回调方法
     *
     * @return invokeCallback 回调方法
     */
    public INettyInvokeCallback getInvokeCallback() {
        return invokeCallback;
    }
    
    /**
     * 功能说明: 设置回调方法
     *
     * @param invokeCallback 回调方法
     */
    public void setInvokeCallback(INettyInvokeCallback invokeCallback) {
        this.invokeCallback = invokeCallback;
    }
    
    @Override
    public String toString() {
        return "ResponseFuture [responseCommand=" + responseCommand + ", sendRequestOK=" + this.sendRequestOK + ", opaque=" + opaque
            + ", timeoutMillis=" + (System.currentTimeMillis() - this.beginTimestamp) + ", beginTimestamp=" + new Date(this.beginTimestamp)
            + ", countDownLatch=" + this.countDownLatch.getCount() + "]";
    }
}
